from cProfile import label
from generator import generator
from alg import Sort
import numpy as np
import matplotlib.pyplot as plt

class SortError(Exception):
    # 定义一个错误类型用于抛出
    def __init__(self, name) -> None:
        self.name = name

    def __str__(self) -> str:
        return str(self.name) + " " + "SortError\n"

class Test:

    def __init__(self, target_list):
        self.test_list = target_list[0]
        self.sorted_list = target_list[1]
        self.list_len = len(self.test_list)
        
        # 用一个列表储存每组数据构成的 sort 类
        self.testm = []
        for i in range(self.list_len):
            test_i = Sort(self.test_list[i], self.sorted_list[i])
            self.testm.append(test_i)

    def __str__(self) -> str:
        str_out = ""
        for i in range(self.list_len):
            str_out += "第{}组：\n".format(i+1)
            str_out += str(self.testm[i]) + "\n" + "{:-^20}".format("*") + "\n"
        return str_out[:-1]

    def judge(func):
        """
        函数装饰器
        判断每种排序算法是否可以成功排序；
        若不能, 则显示排序错误的数据集, 并抛出一个SortError异常
        若排序成功, 则返回一个名为 time_cost 的列表储存每一组数据集在该算法下对应的运行时间
        """
        def warpper(self):
            re, sorted_list, time_cost = func(self)
            error_list = []
            for i in range(len(re)):
                if re[i] != sorted_list[i]:
                    error_list.append(i)
            if error_list != []:
                for i in error_list:
                    print("第{}组排序错误\n".format(i))
                    print("排序结果：" + str(re[i]) + "\n")
                    print("预期结果：" + str(sorted_list[i]) + "\n")
                    raise SortError(func.__name__)
            else:
                return time_cost
        return warpper

    @judge
    def InS_test(self):
        time_cost = []     # 算法的平均用时单位ms
        result_list = []    # 存储每一组经过排序后的结果
        for i in range(self.list_len):
            sort_result = self.testm[i].InS()
            # 也许这一部分也可以放到装饰器里面，但是会产生“InS”未定义的异常，下同
            result_list.append(sort_result[0])
            time_cost.append(sort_result[1])
        return [result_list, self.sorted_list, time_cost]
            # print("第 {} 组数据测试结果为：{}\n".format(i+1, sort_result[0]==self.sorted_list[i]))
            # print("用时：{}ms\n".format(sort_result[1]))
            # print("{:-^30}\n".format("*"))

    @judge
    def ShellS_test(self):
        time_cost = []     # 算法的平均用时单位ms
        result_list = []    # 存储每一组经过排序后的结果
        for i in range(self.list_len):
            sort_result = self.testm[i].ShellS()
            result_list.append(sort_result[0])
            time_cost.append(sort_result[1])
        return [result_list, self.sorted_list, time_cost]

    @judge
    def BubbleS_test(self):
        time_cost = []     # 算法的平均用时单位ms
        result_list = []    # 存储每一组经过排序后的结果
        for i in range(self.list_len):
            sort_result = self.testm[i].BubbleS()
            result_list.append(sort_result[0])
            time_cost.append(sort_result[1])
        return [result_list, self.sorted_list, time_cost]

    @judge
    def QuickS_test(self):
        time_cost = []     # 算法的平均用时单位ms
        result_list = []    # 存储每一组经过排序后的结果
        for i in range(self.list_len):
            sort_result = self.testm[i].QuickS()
            result_list.append(sort_result[0])
            time_cost.append(sort_result[1])
        return [result_list, self.sorted_list, time_cost]

    @judge
    def HeapS_test(self):
        time_cost = []     # 算法的平均用时单位ms
        result_list = []    # 存储每一组经过排序后的结果
        for i in range(self.list_len):
            sort_result = self.testm[i].HeapS()
            result_list.append(sort_result[0])
            time_cost.append(sort_result[1])
        return [result_list, self.sorted_list, time_cost]

    @judge
    def MergeS_test(self):
        time_cost = []     # 算法的平均用时单位ms
        result_list = []    # 存储每一组经过排序后的结果
        for i in range(self.list_len):
            sort_result = self.testm[i].MergeS()
            result_list.append(sort_result[0])
            time_cost.append(sort_result[1])
        return [result_list, self.sorted_list, time_cost]


def draw_res(num_list=[10, 50, 100, 300, 500, 800, 1000, 1500]):
    test_lists = []
    
    # 得到在 num_list 规模下的每种排序方法的运行时间
    for i in num_list:
        gen_list = generator(Num=5, length=i)
        test_list = Test(gen_list.output())

        # 计算每一个排序方法的平均运行时间
        ins_time = np.mean(test_list.InS_test())
        shell_time = np.mean(test_list.ShellS_test())
        bubble_time = np.mean(test_list.BubbleS_test())
        quick_time = np.mean(test_list.QuickS_test())
        heap_time = np.mean(test_list.HeapS_test())
        merge_time = np.mean(test_list.MergeS_test())

        time_list = [ins_time, shell_time, bubble_time, quick_time, heap_time, merge_time]
        test_lists.append(time_list)
    
    # 绘图
    fun_list = ["InS", "ShellS", "BubbleS", 
                "QuickS", "HeapS", "MergeS"]
    color_list = ["#14517c", "#2f7fc1", "#96c37d", 
                  "#f3d266", "#d8383a", "#c497b2"]
    test_lists = np.array(test_lists)
    for i in range(6):
        plt.plot(num_list, test_lists[:,i], label=fun_list[i], color=color_list[i])
    plt.legend()
    plt.grid(linewidth=0.25)
    plt.show()


if __name__ == "__main__":
    # test_sorted_list = generator(Num=5, length=10)
    # a = Test(test_sorted_list.output())
    # # print(a)
    # print(a.InS_test())
    # # print(a.MergeS_test())
    draw_res()